package sdk

import (
	"crypto/md5"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"sort"
	"strings"
)

const (
	POST = "post"
	GET  = "get"
)

type Client struct {
	appKey    string
	appSecret string
	version   string
}

func NewClientWithAccessKey(appKey, appSecret, version string) (*Client, *Error) {
	if appKey == "" || appSecret == "" || version == "" {
		return nil, &Error{
			Code: "10001",
			Msg:  "请完善参数",
		}
	}
	return &Client{
		appKey:    appKey,
		appSecret: appSecret,
		version:   version,
	}, nil
}

func (c *Client) Check() bool {
	if c.appKey == "" || c.appSecret == "" || c.version == "" {
		return false
	}
	return true
}

func (c *Client) Request(apiUrl string, params map[string]string, method string) (string, *Error) {
	if !c.Check() {
		return "", &Error{
			Code: "10001",
			Msg:  "请完善参数: app key, app secret, version",
		}
	}
	method = strings.ToLower(method)
	if method != GET && method != POST {
		return "", &Error{
			Code: "10001",
			Msg:  "method错误",
		}
	}
	data := url.Values{}
	_, doParams := c.makeSign(params)
	for k, v := range doParams {
		data.Set(k, v)
	}
	var req *http.Request
	var rsp *http.Response
	var err error
	if method == GET {
		rsp, err = http.Get(apiUrl + "?" + data.Encode())
		if err != nil {
			return "", nil
		}
	} else {
		body := strings.NewReader(data.Encode())
		req, err = http.NewRequest(POST, apiUrl, body)
		if err != nil {
			return "", &Error{
				Code: "10001",
				Msg:  err.Error(),
			}
		}
		req.Header.Set("Content-Type", "application/json")
		cli := http.Client{}
		rsp, err = cli.Do(req)
		if err != nil {
			return "", &Error{
				Code: "10001",
				Msg:  err.Error(),
			}
		}
	}
	rs, err := ioutil.ReadAll(rsp.Body)
	if err != nil {
		return "", &Error{
			Code: "10001",
			Msg:  err.Error(),
		}
	}
	return string(rs), nil
}

func (c *Client) makeSign(params map[string]string) (string, map[string]string) {
	var keys []string
	var data string
	if _, ok := params["appKey"]; !ok {
		params["appKey"] = c.appKey
	}
	if _, ok := params["version"]; !ok {
		params["version"] = c.version
	}
	for key, _ := range params {
		keys = append(keys, key)
	}
	sort.Strings(keys)
	//拼接
	for _, k := range keys {
		data = fmt.Sprintf("%s%s=%s&", data, k, params[k])
	}
	data = fmt.Sprintf("%skey=%s", data, c.appSecret)
	data = strings.Trim(data, "&")
	m := md5.New()
	m.Write([]byte(data))
	sign := strings.ToUpper(fmt.Sprintf("%x", m.Sum(nil)))
	params["sign"] = sign
	return sign, params
}
